﻿using System.Collections.Generic;
using BasicParts;

namespace ParallaxMachine
{
    public class ParallaxManager
    {
        #region Fields and Constructor
        /// <summary>A list of lists, sorted as a list of horizontal
        /// backgrounds in each list of vertical backgrounds.</summary>

        /// <summary>A list of lists, sorted as [x, y]. </summary>
        //public List<Background[,]> backgrounds;
        //public Dictionary<int, Vector2> layerSpeeds;

        public List<Layer> layers;

        /// <summary>
        /// Creates a new ParallaxService. Add backgrounds and assign values to 
        /// layerSpeeds, then call the UpdateBackgrounds(...) method.
        /// </summary>
        public ParallaxManager()
        {
            //backgrounds = new List<Background[,]>();
            //layerSpeeds = new Dictionary<int, Vector2>();

            layers = new List<Layer>();
        }
        #endregion //Fields and Constructors

        #region Update
        /// <summary>
        /// Updates the backgrounds according to by how much the camera has moved.
        /// </summary>
        /// <param name="camMovement">By how much the camera has moved.</param>
        public void UpdateBackgrounds(Vector2 camMovement)
        {
            int currentIndex;
            Vector2 layerSpeed;
            Point layerSize;
            Vector2 move;

            foreach (Layer layer in layers)
            {
                currentIndex = layer.index;
                layerSpeed = layer.speed;
                layerSize = layer.size;
                move = camMovement * layerSpeed;
                for (int y = 0; y < layer.backgrounds.GetLength(1); y++)
                    for (int x = 0; x < layer.backgrounds.GetLength(0); x++)
                    {
                        Image b = layer.backgrounds[x, y];
                        b.Position -= move;

                        //Check if this background is too far in any direction.
                        //If so, we move it to the opposite end of the layer.
                        if (b.Position.X < -b.Size.X)
                            b.Position += new Vector2(layerSize.X, 0);
                        else if (b.Position.X > layerSize.X - b.Size.X)
                            b.Position -= new Vector2(layerSize.X, 0);

                        if (b.Position.Y < -b.Size.Y)
                            b.Position += new Vector2(0, layerSize.Y);
                        else if (b.Position.Y > layerSize.Y - b.Size.Y)
                            b.Position -= new Vector2(0, layerSize.Y);
                    }
            }
            //foreach (Background b in backgrounds)
            //{
            //    if (b.LayerIndex != currentIndex)
            //    {
            //        currentIndex = b.LayerIndex;
            //        layerSpeeds.TryGetValue(currentIndex, out layerSpeed);
            //        move = camMovement * layerSpeed;
            //        layerHeight = LayerSize(currentIndex).Y;
            //        b.Position -= move;
            //    }
            //    else
            //        b.Position = lastBackgroundPos;
            //    lastBackgroundPos.Y = b.Position.Y + b.Size.Y;
            //    if (b.Position.Y < -b.Size.Y)
            //        b.Position += new Vector2(0, layerHeight);
            //    else if (b.Position.Y > layerHeight - b.Size.Y)
            //        b.Position -= new Vector2(0, layerHeight);
            //}
        }
        #endregion //Update

        #region Background List Methods
        public void AddLayer(Layer layer)
        {
            layers.Add(layer);
        }
        public void AddLayer(Image[,] backgrounds, Vector2 speed, int index)
        {
            layers.Add(new Layer(backgrounds, speed, index));
        }

        /// <summary>
        /// Inserts a background to a given layer. Note that the layer must first have been created.
        /// </summary>
        public bool AddBackground(Image background, Layer layer, int yIndex)
        {
            layer.backgrounds[layer.backgrounds.GetLength(0), yIndex] = background;
            return true;
        }
        /// <summary>
        /// Inserts a background to a given layer. Note that the layer must first have been created.
        /// </summary>
        public bool AddBackground(Image background, int layerIndex, int yIndex)
        {
            Layer layer = layers.Find(l => l.index == layerIndex);
            if (layer == null)
                return false;
            layer.backgrounds[layer.backgrounds.GetLength(0), yIndex] = background;
            return true;
            //int index = backgrounds.FindIndex(bg => bg.LayerIndex <= b.LayerIndex);
            //backgrounds.Insert(index != -1 ? index : backgrounds.Count, b);
        }
        /// <summary> Removes a given background. </summary>
        /// <param name="b">The background to remove.</param>
        /// <returns>If a background was removed.</returns>
        //public bool RemoveBackground(Background b)
        //{
        //    return backgrounds.Remove(b);
        //}
        /// <summary> Removes all backgrounds from a given layer. </summary>
        /// <param name="layerIndex">The layer index from which to remove backgrounds.</param>
        /// <returns>How many backgrounds were removed.</returns>
        public int RemoveLayer(int layerIndex)
        {
            return layers.RemoveAll(l => l.index == layerIndex);
            //return backgrounds.RemoveAll(b => b.LayerIndex == layerIndex);
        }
        /// <summary> Removes all backgrounds. </summary>
        public void ClearBackgrounds()
        {
            layers.Clear();
        }
        #endregion //Background List Methods

        #region Helper Methods
        /// <summary>
        /// Sums up the total size of all backgrounds on a given layer index.
        /// </summary>
        /// <param name="layer">Which layer you want the size of.</param>
        /// <returns>The total size of the layer.</returns>
        //private Point LayerSize(int layer)
        //{
        //    Point layerSize = new Point();
        //    foreach (Background b in backgrounds)
        //        if (b.LayerIndex == layer)
        //            layerSize += b.Size;
        //    return layerSize;
        //}

        /// <summary>
        /// Sorts the list of backgrounds according to layer index.
        /// </summary>
        //private void SortBackgrounds()
        //{
        //    backgrounds.Sort(CompareBackgroundsByLayerIndex);
        //    int currentIndex = 0;
        //    int widthPos = 0;
        //    foreach (IBackground b in backgrounds)
        //        if (b.LayerIndex != currentIndex)
        //        {
        //            currentIndex = b.LayerIndex;
        //            b.Position.X = widthPos = 0;
        //            widthPos += b.Size.X;
        //        }
        //        else
        //        {
        //            b.Position.X = widthPos;
        //            widthPos += b.Size.X;
        //        }
        //}
        //private int CompareBackgroundsByLayerIndex(IBackground b1, IBackground b2)
        //{
        //    if (b1.LayerIndex < b2.LayerIndex) return -1;
        //    else if (b1.LayerIndex > b2.LayerIndex) return 1;
        //    else return 0;
        //}
        #endregion //Helper Methods
    }
}
